/***********************************************************************************************************
 *** @Author         : jiabao
 *** @Description    :
 *** @Date           : 2023-12-02 15:36:59
 *** @FilePath       : /demo_cc/socket/multicast/src/multicast.cpp
 ***********************************************************************************************************/
#include "multicast.hpp"

Multicast::Multicast(string groupIp, int groupPort) : mGroupIp(groupIp), mGroupPort(groupPort)
{
    int err;
    mSockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (mSockFd == -1)
    {
        perror("socket()");
        return;
    }
    // 增加地址复用
    int optval = 1;
    err = setsockopt(mSockFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (err < 0)
    {
        perror("setsockopt SO_REUSEADDR error.");
    }

    struct sockaddr_in local_addr;
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr.sin_port = htons(mGroupPort);

    err = bind(mSockFd, (struct sockaddr *)&local_addr, sizeof(local_addr));
    if (err < 0)
    {
        perror("bind()");
        return;
    }

    mreq.imr_multiaddr.s_addr = inet_addr((const char *)mGroupIp.c_str());
    mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 如果有多个网卡，需要指定网卡
    err = setsockopt(mSockFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
    if (err < 0)
    {
        perror("setsockopt():IP_ADD_MEMBERSHIP");
        return;
    }
    // mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.66");
    // mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    // err = setsockopt(mSockFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
    // if (err < 0)
    // {
    //     perror("setsockopt():IP_ADD_MEMBERSHIP");
    //     return;
    // }
}

int Multicast::multicastRead(string &s, struct sockaddr_in *from)
{
    int recvLen = 0;
    unsigned int addrLen = sizeof(struct sockaddr_in);
    char buf[1024] = {0};
    recvLen = recvfrom(mSockFd, buf, s.capacity(), 0,
                       (struct sockaddr *)from, (socklen_t *)&addrLen);
    s = buf;
    return recvLen;
}

int Multicast::multicastSend(string s)
{
    int sendLen = 0;
    struct sockaddr_in addrTo;
    unsigned int addrLen = sizeof(addrTo);
    addrTo.sin_addr.s_addr = inet_addr(mGroupIp.c_str());
    addrTo.sin_family = AF_INET;
    addrTo.sin_port = htons(mGroupPort);
    ;
    sendLen = sendto(mSockFd, s.c_str(), s.length(), 0, (struct sockaddr *)&addrTo, addrLen);
    return sendLen;
}

Multicast::~Multicast()
{
    if (mSockFd != 0)
    {
        setsockopt(mSockFd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
        close(mSockFd);
    }
}